﻿using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace ZYing.LiquidThemeEngine.FileProviders
{
    public class LiquidThemeFileProvider : ILiquidThemeFileProvider
    {
        #region LiquidThemeFileInfo
        private readonly struct LiquidThemeFileInfo : ILiquidThemeFileInfo
        {
            private readonly IFileInfo _fileInfo;

            public LiquidThemeFileInfo(IFileInfo fileInfo)
            {
                _fileInfo = fileInfo ?? throw new ArgumentNullException(nameof(fileInfo));
            }

            public bool Exists => _fileInfo.Exists;

            public long Length => _fileInfo.Length;

            public string Name => _fileInfo.Name;

            public DateTimeOffset LastModified => _fileInfo.LastModified;

            public bool IsDirectory => _fileInfo.IsDirectory;

            public Stream CreateReadStream()
            {
                return _fileInfo.CreateReadStream();
            }
        }
        #endregion
        #region LiquidThemeDirectoryContents
        private readonly struct LiquidThemeDirectoryContents : ILiquidThemeDirectoryContents
        {
            private readonly IDirectoryContents _directoryContents;

            public LiquidThemeDirectoryContents(IDirectoryContents directoryContents)
            {
                _directoryContents = directoryContents ?? throw new ArgumentNullException(nameof(directoryContents));
            }

            public bool Exists => _directoryContents.Exists;

            public IEnumerator<ILiquidThemeFileInfo> GetEnumerator()
            {
                if (_directoryContents.Exists)
                {
                    foreach (var item in _directoryContents)
                    {
                        yield return new LiquidThemeFileInfo(item);
                    }
                }
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }

        #endregion



        public IFileProvider FileProvider { get; }
        public string Prefix { get; } = string.Empty;

        public LiquidThemeFileProvider(IFileProvider fileProvider, string prefix)
        {
            FileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
            Prefix = prefix ?? throw new ArgumentOutOfRangeException(nameof(prefix));
        }
        public LiquidThemeFileProvider(IFileProvider fileProvider)
        {
            FileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
        }

        public ILiquidThemeFileInfo GetFileInfo(string theme, string path)
        {
            if (string.IsNullOrWhiteSpace(theme)) throw new ArgumentNullException(nameof(theme));
            if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
            var list = new List<string>();
            if (!string.IsNullOrWhiteSpace(this.Prefix)) list.Add(this.Prefix);
            list.Add(theme);
            list.Add(path);
            var full = Path.Combine(list.ToArray());
            var file = this.FileProvider.GetFileInfo(full);
            return new LiquidThemeFileInfo(file);
        }

        public ILiquidThemeDirectoryContents GetDirectoryContents(string theme, string path)
        {
            if (string.IsNullOrWhiteSpace(theme)) throw new ArgumentNullException(nameof(theme));
            if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
            var list = new List<string>();
            if (!string.IsNullOrWhiteSpace(this.Prefix)) list.Add(this.Prefix);
            list.Add(theme);
            list.Add(path);
            var full = Path.Combine(list.ToArray());
            var dir = this.FileProvider.GetDirectoryContents(full);
            return new LiquidThemeDirectoryContents(dir);
        }

        public IChangeToken Watch(string theme, string filter)
        {
            if (string.IsNullOrWhiteSpace(theme)) throw new ArgumentNullException(nameof(theme));
            if (string.IsNullOrWhiteSpace(filter)) throw new ArgumentNullException(nameof(filter));
            var list = new List<string>();
            if (!string.IsNullOrWhiteSpace(this.Prefix)) list.Add(this.Prefix);
            list.Add(theme);
            list.Add(filter);
            var full = Helper.CombinePath(list.ToArray());
            return this.FileProvider.Watch(full);
        }
    }
}
